import {IDisposable} from "./lifecycle";
import {CallbackList} from "./CallbackList";
import * as types from 'egret/base/common/types';

export interface IBoardcastEvent {
    (...args): void;
}

export interface IBoardcast {
    on(type: string, event: IBoardcastEvent, context?: Object, disposables?: IDisposable[], priority?: number): IDisposable;

    put(type: string, ...args): void;

    pull<T>(type: string, ...args): T;

    pull(type: string, ...args): any;
}

export class Boardcast implements IBoardcast {
    private _callback: CallbackList = new CallbackList();

    private _callbackListMap: { [key: string]: CallbackList } = {};

    on(type: string, event: IBoardcastEvent, context: Object | IDisposable[] = null, disposables: IDisposable[] | number = null, priority?: number): IDisposable {
        if (types.isArray(context)) {
            disposables = context;
            context = null;
        }
        if (typeof (disposables) == 'number') {
            priority = disposables;
            disposables = null;
        }
        if (!this._callbackListMap.hasOwnProperty(type)) {
            this._callbackListMap[type] = new CallbackList();
        }
        this._callbackListMap[type].add(event, context, null, priority || 0);
        var dispose = {
            dispose: () => {
                this._callbackListMap[type].remove(event, context);
            }
        };
        if (types.isArray(disposables)) {
            disposables.push(dispose);
        }
        return dispose;
    }

    pull(type: string, ...args): any {
        if (this._callbackListMap.hasOwnProperty(type)) {
            return this._callbackListMap[type].pull(...args);
        }
        return args[0];
    }

    put(type: string, ...args): void {
        if (this._callbackListMap.hasOwnProperty(type)) {
            this._callbackListMap[type].invoke(...args);
        }
        if (type != '*' && this._callbackListMap.hasOwnProperty('*')) {
            this._callbackListMap['*'].invoke(...[type].concat(args));
        }
    }
}

var boardcast = new Boardcast();

export function on(type: string, call: IBoardcastEvent, context: Object | IDisposable[] = null, disposables: IDisposable[] | number = null, priority?: number): IDisposable {
    return boardcast.on.call(boardcast, type, call, context, disposables, priority);
}

export function pull<T>(type: string, ...args): T;
export function pull(type: string, ...args): any {
    return boardcast.pull.apply(boardcast, [type].concat(args));
}

export function put(type: string, ...args): void {
    boardcast.put.apply(boardcast, [type].concat(args));
}

global['put'] = put;
